package com.github.base.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.base.domain.Permission;
import com.github.base.domain.Role;
import com.github.base.domain.RolePermission;
import com.github.base.dto.role.RoleDTO;
import com.github.base.exception.CommonException;
import com.github.base.global.Const;
import com.github.base.mapper.PermissionMapper;
import com.github.base.mapper.RoleMapper;
import com.github.base.mapper.RolePermissionMapper;
import com.github.base.service.RoleService;
import com.github.base.vo.role.RolePageListVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 角色基础操作实现
 *
 * @author GongShaopeng
 * create by 2021-01-28
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {
    private final RoleMapper roleMapper;
    private final PermissionMapper permissionMapper;
    private final RolePermissionMapper rolePermissionMapper;
    private final RolePermissionServiceImpl rolePermissionService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(RoleDTO roleDTO) {
        // 验证角色名称或角色编码不能重复
        Role role = roleMapper.selectOne(Wrappers.lambdaQuery(Role.class)
                .eq(Role::getRoleCode, roleDTO.getRoleCode())
                .eq(Role::getState, Const.YES));

        if (role != null) {
            throw new CommonException("角色编号重复");
        }

        // 新建角色
        Role roleNew = new Role();
        BeanUtils.copyProperties(roleDTO, roleNew);
        roleNew.setOperable(Const.YES);
        roleNew.setState(Const.YES);
        roleNew.setCreateTime(LocalDateTime.now());
        roleNew.setModifyTime(LocalDateTime.now());
        roleNew.insert();
    }

    @Override
    public Page<RolePageListVO> pageList(Integer current, Integer size, String roleName,
                                         Integer usable, String roleDesc) {

        current = (current == null || current < 1) ? 1 : current;
        size = (size == null || size < 1) ? 20 : size;
        Page<RolePageListVO> page = new Page<>(current, size);
        return roleMapper.pageList(page, roleName, usable, roleDesc);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(RoleDTO roleDTO) {
        // 查询角色
        Role role = this.getValidById(roleDTO.getId());

        // 验证角色名称、编码是否修改
        if (!role.getRoleName().equals(roleDTO.getRoleName())) {
            Role roleOld = roleMapper.selectOne(Wrappers.lambdaQuery(Role.class)
                    .eq(Role::getRoleName, roleDTO.getRoleName())
                    .eq(Role::getState, Const.YES));
            if (roleOld != null) throw new CommonException("角色名称已存在");
        }
        if (!role.getRoleCode().equals(roleDTO.getRoleCode())) {
            Role roleOld = roleMapper.selectOne(Wrappers.lambdaQuery(Role.class)
                    .eq(Role::getRoleCode, roleDTO.getRoleCode())
                    .eq(Role::getState, Const.YES));
            if (roleOld != null) throw new CommonException("角色编码已存在");
        }

        // 修改信息
        BeanUtils.copyProperties(roleDTO, role);
        role.updateById();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        // 查询角色
        Role role = this.getValidById(id);
        Integer integer = roleMapper.selectUserCountByRole(role.getId());
        if (integer != null && integer > 0) {
            throw new CommonException("角色已有用户使用,不可删除");
        }
        // 修改删除状态
        role.setState(Const.NO);
        role.updateById();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void toggle(Long id) {
        // 查询角色
        Role role = this.getValidById(id);

        // 切换可用状态
        role.setUsable(role.getUsable().equals(Const.YES) ? Const.NO : Const.YES);
        role.updateById();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void allotPermission(Long id, Integer[] permissionIds) {
        // 查询角色
        this.getValidById(id);

        // 删除之前所有关联
        rolePermissionMapper.delete(Wrappers.lambdaQuery(RolePermission.class).eq(RolePermission::getRoleId, id));

        // 查询资源列表
        List<Permission> permissions = permissionMapper.selectList(Wrappers.lambdaQuery(Permission.class)
                .eq(Permission::getState, Const.YES)
                .in(Permission::getId, Arrays.stream(permissionIds).collect(Collectors.toSet())));
        if (permissions.isEmpty()) return;
        // 建立新关系
        Set<RolePermission> rolePermissionSet = permissions.stream().map(item -> {
            RolePermission rolePermission = new RolePermission();
            rolePermission.setRoleId(id);
            rolePermission.setPermissionId(item.getId());
            return rolePermission;
        }).collect(Collectors.toSet());

        rolePermissionService.saveBatch(rolePermissionSet);
    }

    @Override
    public Set<Long> permissions(Long id) {
        List<RolePermission> rolePermissions = rolePermissionMapper
                .selectList(Wrappers.lambdaQuery(RolePermission.class).eq(RolePermission::getRoleId, id));
        if (rolePermissions.isEmpty()) return new HashSet<>();
        return rolePermissions.stream().map(RolePermission::getPermissionId).collect(Collectors.toSet());
    }


    /**
     * 根据角色Id查询有效的角色信息
     *
     * @param roleId 角色Id
     * @return 返回角色实体
     */
    private Role getValidById(Long roleId) {
        // 查询角色
        Role role = roleMapper.selectOne(Wrappers.lambdaQuery(Role.class)
                .eq(Role::getId, roleId)
                .eq(Role::getState, Const.YES));
        if (role == null) throw new CommonException("角色id不存在");
        return role;
    }
}
